package tool.soft

import akka.stream.Materializer

import java.io.File
import dao._
import implicits.Implicits._
import models.Tables
import models.Tables._
import org.joda.time.DateTime
import play.api.data.FormBinding
import play.api.libs.ws.WSClient
import play.api.mvc.{AnyContent, Request}
import play.twirl.api.Html
import shared.Pojo._
import tool.Pojo._
import tool.plot._
import tool.soft.AllSoft.SoftBT
import tool._

import scala.language.postfixOps
import play.api.i18n.Messages
import utils.Utils
import upickle.default._

/** Created by yz on 15/9/2020
  */
object ParCorSoft extends ParCorSoftT with SoftBT {

  override def getFileInfos(workspaceDir: File, index: Int)(implicit
      matrixFileDataDao: MatrixFileDataDao,
      messages: Messages
  ): List[FileInfoData] = {
    List(
      FileInfoData("Correlation_Heatmap.pdf", messages("correlationHeatmap")),
      FileInfoData("r_Matrix.csv", messages("rMatrix")),
      FileInfoData("P_Matrix.csv", messages("pMatrix")),
      FileInfoData("Corrected_P_Matrix.csv", messages("correctedPMatrix")),
      FileInfoData("Network_Nodes_for_Cytoscape.csv", messages("networkNodesForCytoscape")),
      FileInfoData("Network_Edges_for_Cytoscape.xls", messages("networkEdgesForCytoscape")),
      FileInfoData("Network_for_Cytoscape.gml", messages("networkForCytoscape"))
    )
  }

  override def produceConfigFile(workspaceDir: File, index: Int)(implicit
      request: Request[AnyContent],
      formBinding: FormBinding
  ) = {
    data.lines().toTxtFile(Tool.getCalculateConfigTxtFile(workspaceDir))
    Tool.producePlotConfigFile(SFormTool.getAllPlotData, CorNetwork, workspaceDir)
    plot.CorHeatmapPlot.initConfigFile(workspaceDir, idStr = "")
  }

  override def getResultHtml(missionId: Int)(implicit request: Request[AnyContent], messages: Messages): Html = {
    views.html.user.mission.parCorResult(missionId)
  }

  def getArg(implicit request: Request[AnyContent], messages: Messages, formBinding: FormBinding): ujson.Value = {
    val corMethodStr = data.corMethod.capitalize
    val fdrMethodStr = data.fdrMethod match {
      case "fdr" => messages("FDRBH")
      case "bonferroni" => "Bonferroni"
      case "holm" => "Holm"
    }
    ujson.Obj(
      messages("method") -> corMethodStr,
      messages("adjustPBy") -> fdrMethodStr,
      messages("correlationCutoff") -> data.coe,
      messages("pValueCutoff") -> data.p,
      messages("adjustedPCutoff") -> data.fdr
    )
  }

  override def getCommandData(workspaceDir: File, resultDir: File, index: Int): List[CommandData] = {
    val solutionFile = new File(Tool.dataDir, "color_solution/color_solution_1.txt")
    val rawDataFile = new File(workspaceDir, "AllMet_Raw.txt")
    val value = Utils.configFile2Json(workspaceDir)
    val data = value.transform(reader[ParCorData])
    val rFileName = if (data.hasExtraDataFile) {
      if (data.hasConfounderFile) {
        "diff_confounder_cor_calculate"
      } else {
        "diff_upload_cor_calculate"
      }
    } else "diff_self_calculate"
    val command =
      s"""
         |${"Rscript".condaPath()} ${new File(Tool.rPath, s"${rFileName}.R").unixPath}
         |${"Rscript".condaPath()} ${new File(Tool.rPath, "node_attr_calculate.R").unixPath}
           """.stripMargin
    val plotCommand = plot.CorHeatmapPlot.getCommand(workspaceDir, "")
    List(CommandData(workspaceDir, List(command, plotCommand)))
  }

  override def getHtml(missionName: String, missionId: Option[Int])(implicit
      request: Request[AnyContent],
      messages: Messages
  ): Html = {
    views.html.user.soft.parCor(missionName, missionId)
  }

  override def getMission(implicit
      request: Request[AnyContent],
      matrixFileDataDao: MatrixFileDataDao,
      messages: Messages,
      formBinding: FormBinding
  ): Tables.MissionRow = {
    val input = if (data.hasExtraDataFile) {
      if (data.hasConfounderFile) {
        List(data.file, data.extraFile, data.confounderFile)
      } else {
        List(data.file, data.extraFile)
      }
    } else {
      List(data.file)
    }
    val argJson = getArg
    MissionRow(
      id = 0,
      missionName = s"${data.missionName}",
      kind = nameStr,
      userId = userId,
      startTime = new DateTime(),
      state = "preparing",
      arg = argJson,
      input = input
    )
  }

  override def produceInputFile(
      workspaceDir: File
  )(implicit request: Request[AnyContent], dao: MyDao, formBinding: FormBinding): Any = {
    Utils.t2ConfigFile(workspaceDir, data)
    val rawDataFile = new File(workspaceDir, "AllMet_Raw.txt")
    Tool.produceRawMetaboliteFile(userId, data.file, rawDataFile)
    if (data.hasExtraDataFile) {
      val extraDataFile = new File(workspaceDir, "extra_data.txt")
      Tool.produceRawMetaboliteFile(userId, data.extraFile, extraDataFile)
      if (data.hasConfounderFile) {
        val confounderDataFile = new File(workspaceDir, "confounder_data.txt")
        Tool.produceRawMetaboliteFile(userId, data.confounderFile, confounderDataFile)
      }
    }

  }

  override def data(implicit request: Request[AnyContent], formBinding: FormBinding) = {
    FormTool.parCorForm.bindFromRequest().get
  }

  override def resultDeal(workspaceDir: File, resultDir: File)(implicit
      ws: WSClient,
      materializer: Materializer
  ): Unit = {
    workspaceDir
      .listFiles(Tool.fileNameFilter)
      .filterNot { file =>
        file.getName == "Network_Edges_for_Cytoscape.csv"
      }
      .foreach { file =>
        file.fileCopyToDir(resultDir)
      }
  }

}
